﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Threading;
using System.Drawing;

namespace BaseHelper.Http
{

    public struct RequestInfo
    {
        public string UserAgent;
        public string ContentType;
        public string Accept;
        public string Referer;
        public string AcceptEncoding;
        public string AcceptLanguage;
        public bool AllowAutoRedirect;
        public CookieContainer Cookie;
        public Encoding Encoding;
        public IWebProxy Proxy;

    }



    public class HttpHelper
    {


        public RequestInfo RequestInfo = new RequestInfo();

        private int delay = 100;
        private int maxTry = 30;
        private int currentTry = 0;
        public IWebProxy Proxy;
        private WebHeaderCollection webHeader = null;

        public HttpHelper()
        {
            RequestInfo.Accept = "*/*";
            RequestInfo.ContentType = "application/x-www-form-urlencoded";
            RequestInfo.UserAgent = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36";
            RequestInfo.AllowAutoRedirect = false;
            RequestInfo.Encoding = Encoding.UTF8;
            RequestInfo.Cookie = new CookieContainer();

        }


        public CookieContainer Cookies
        {
            get
            {
                return RequestInfo.Cookie;
            }
            set
            {
                RequestInfo.Cookie = value;
            }
        }


        public Encoding Encoding
        {
            get
            {
                return RequestInfo.Encoding;
            }
            set
            {
                RequestInfo.Encoding = value;
            }
        }

        public string GetHeader
        {
            get
            {
                string str = "";
                for (int i = 0; i < webHeader.Count; i++)
                {
                    str += webHeader.GetKey(i) + "=" + webHeader.Get(i) + "\r\n";
                }
                return str;

            }
        }

        public int NetworkDelay
        {
            get
            {
                Random r = new Random();
                return (r.Next(delay, delay * 2));
            }
            set
            {
                delay = value;
            }
        }

        public int MaxTry
        {
            get
            {
                return maxTry;
            }
            set
            {
                maxTry = value;
            }
        }

        public string GetCookie(string url, string keyname)
        {
            string getCookie = RequestInfo.Cookie.GetCookieHeader(new Uri(url));
            if (keyname == "")
                return getCookie;
            string getValue = "";
            foreach (Cookie readCookie in RequestInfo.Cookie.GetCookies(new Uri(url)))
            {
                if (readCookie.Name.ToLower().Equals(keyname.ToLower()))
                {
                    getValue = readCookie.Value;
                    break;
                }
            }
            return getValue;
        }

        public string GetCookie(string url)
        {
            string getCookie = RequestInfo.Cookie.GetCookieHeader(new Uri(url));
            string getValue = "";
            foreach (Cookie readCookie in RequestInfo.Cookie.GetCookies(new Uri(url)))
            {
                getValue += readCookie.Name + "=" + readCookie.Value + "; ";

            }
            return getValue;
        }

        public void SetCookie(string cookies, string domain)
        {
            cookies = cookies.Replace(" ", "");
            cookies = cookies.Substring(0, cookies.Length - 1);
            string[] cookie = cookies.Split(';');
            foreach (string ck in cookie)
            {
                string[] sp = ck.Split('=');
                RequestInfo.Cookie.Add(new Cookie(sp[0], sp[1], "/", domain));
            }

        }


        public string Get(string url)
        {
            return GetHtml(url, null, ref RequestInfo.Cookie, null, RequestInfo.Referer, RequestInfo.Accept, RequestInfo.ContentType, RequestInfo.UserAgent, RequestInfo.AllowAutoRedirect);
        }
        public string Get(string url, Encoding e)
        {
            RequestInfo r = new RequestInfo();
            r = RequestInfo;
            r.ContentType = "application/x-javascript; charset=" + e.HeaderName;
            r.Encoding = e;
            RequestInfo.Encoding = e;
            return Get(url, r);

        }
        public string Get(string url, CookieContainer cc)
        {
            return GetHtml(url, null, ref cc, null, RequestInfo.Referer, RequestInfo.Accept, RequestInfo.ContentType, RequestInfo.UserAgent, RequestInfo.AllowAutoRedirect);
        }
        public string Get(string url, string rferer)
        {
            return GetHtml(url, null, ref RequestInfo.Cookie, null, rferer, RequestInfo.Accept, RequestInfo.ContentType, RequestInfo.UserAgent, RequestInfo.AllowAutoRedirect);
        }
        public string Get(string url, bool AllowAutoRedirect, string useragent)
        {
            return GetHtml(url, null, ref RequestInfo.Cookie, null, null, null, null, useragent, AllowAutoRedirect);
        }
        public string Get(string url, string referer, string accept, string contenttype, string useragent)
        {
            return GetHtml(url, null, ref RequestInfo.Cookie, null, referer, accept, contenttype, useragent, RequestInfo.AllowAutoRedirect);
        }
        public string Get(string url, RequestInfo RequestInfo)
        {
            return GetHtml(url, null, ref RequestInfo.Cookie, null, RequestInfo.Referer, RequestInfo.Accept, RequestInfo.ContentType, RequestInfo.UserAgent, RequestInfo.AllowAutoRedirect);
        }

        public string Post(string url, string postData)
        {
            return GetHtml(url, postData, ref RequestInfo.Cookie, null, RequestInfo.Referer, RequestInfo.Accept, RequestInfo.ContentType, RequestInfo.UserAgent, RequestInfo.AllowAutoRedirect);
        }
        public string Post(string url, string postData, CookieContainer cc)
        {
            return GetHtml(url, postData, ref cc, null, RequestInfo.Referer, RequestInfo.Accept, RequestInfo.ContentType, RequestInfo.UserAgent, RequestInfo.AllowAutoRedirect);

        }
        public string Post(string url, string postData, string rferer)
        {
            return GetHtml(url, postData, ref RequestInfo.Cookie, null, rferer, RequestInfo.Accept, RequestInfo.ContentType, RequestInfo.UserAgent, RequestInfo.AllowAutoRedirect);

        }
        public string Post(string url, string postData, string referer, string accept, string contenttype, string useragent)
        {
            return GetHtml(url, postData, ref RequestInfo.Cookie, null, referer, accept, contenttype, useragent, RequestInfo.AllowAutoRedirect);
        }
        public string Post(string url, string postData, RequestInfo RequestInfo)
        {
            return GetHtml(url, postData, ref RequestInfo.Cookie, null, RequestInfo.Referer, RequestInfo.Accept, RequestInfo.ContentType, RequestInfo.UserAgent, RequestInfo.AllowAutoRedirect);
        }

        public string GetHtml(string url, string postData, CookieContainer cookieContainer, IWebProxy proxy)
        {
            return GetHtml(url, postData, ref cookieContainer, proxy, RequestInfo.Referer, RequestInfo.Accept, RequestInfo.ContentType, RequestInfo.UserAgent, RequestInfo.AllowAutoRedirect);

        }
        public string GetHtml(string url, string postData, ref CookieContainer cookieContainer, IWebProxy proxy, string referer, string accept, string contenttype, string useragent, bool AllowAutoRedirect)
        {
            ServicePointManager.Expect100Continue = false;

            Thread.Sleep(NetworkDelay);//等待

            currentTry++;

            HttpWebRequest httpWebRequest = null;

            HttpWebResponse httpWebResponse = null;
            try
            {
                if (url.ToLower().StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                    httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
                    httpWebRequest.ProtocolVersion = HttpVersion.Version11;
                }
                else
                    httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);

                if (proxy != null)
                    httpWebRequest.Proxy = proxy;

                if (cookieContainer != null)
                    httpWebRequest.CookieContainer = cookieContainer;
                else
                    httpWebRequest.CookieContainer = RequestInfo.Cookie;

                if (referer != null && referer.Length > 0)
                    httpWebRequest.Referer = referer;

                if (contenttype != null && contenttype.Length > 0)
                    httpWebRequest.ContentType = contenttype;

                if (accept != null && accept.Length > 0)
                    httpWebRequest.Accept = accept;

                if (useragent != null && useragent.Length > 0)
                    httpWebRequest.UserAgent = useragent;

                httpWebRequest.AllowAutoRedirect = AllowAutoRedirect;

                httpWebRequest.ServicePoint.ConnectionLimit = maxTry;
                httpWebRequest.KeepAlive = true;

                httpWebRequest.Method = postData != null ? "POST" : "GET";
                //  httpWebRequest.Timeout = 10000;

                if (postData != null)
                {


                    byte[] byteRequest = RequestInfo.Encoding.GetBytes(postData);
                    httpWebRequest.ContentLength = byteRequest.Length;
                    Stream stream = httpWebRequest.GetRequestStream();
                    stream.Write(byteRequest, 0, byteRequest.Length);
                    stream.Close();
                }


                httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                Stream responseStream = httpWebResponse.GetResponseStream();
                StreamReader streamReader = new StreamReader(responseStream, RequestInfo.Encoding);
                string html = streamReader.ReadToEnd();
                streamReader.Close();
                responseStream.Close();


                //currentTry = 0;

                webHeader = new WebHeaderCollection();
                webHeader = httpWebResponse.Headers;
                httpWebRequest.Abort();
                httpWebResponse.Close();

                if (cookieContainer != null)
                {
                    foreach (Cookie cookie in httpWebResponse.Cookies)
                    {
                        //Console.WriteLine(cookie.ToString());
                        cookieContainer.Add(cookie);
                    }
                }
                else
                {
                    foreach (Cookie cookie in httpWebResponse.Cookies)
                    {
                        RequestInfo.Cookie.Add(cookie);
                    }

                }

                return html;
            }
            catch (Exception ex)
            {
                if (httpWebRequest != null)
                {
                    httpWebRequest.Abort();
                } if (httpWebResponse != null)
                {
                    httpWebResponse.Close();
                }
                Console.WriteLine("BaseHelper.Http.HttpHelper.cs.Get:" + ex.Message);
                return "";
            }
        }

        public string PostBytes(string url, List<byte[]> postDatas, string referer, string accept, string contenttype)
        {
            ServicePointManager.Expect100Continue = false;

            Thread.Sleep(NetworkDelay);//等待

            currentTry++;

            HttpWebRequest httpWebRequest = null;

            HttpWebResponse httpWebResponse = null;
            try
            {
                if (url.ToLower().StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                    httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
                    httpWebRequest.ProtocolVersion = HttpVersion.Version10;
                }
                else
                    httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);

                httpWebRequest.CookieContainer = RequestInfo.Cookie;

                if (referer != null && referer.Length > 0)
                    httpWebRequest.Referer = referer;

                if (contenttype != null && contenttype.Length > 0)
                    httpWebRequest.ContentType = contenttype;

                if (accept != null && accept.Length > 0)
                    httpWebRequest.Accept = accept;

                httpWebRequest.AllowAutoRedirect = false;


                httpWebRequest.ServicePoint.ConnectionLimit = maxTry;

                httpWebRequest.Method = postDatas != null ? "POST" : "GET";
                // httpWebRequest.Timeout = 10000;

                if (postDatas != null)
                {
                    int totalLength = 0;

                    foreach (byte[] b in postDatas)
                    {
                        totalLength += b.Length;
                    }
                    httpWebRequest.ContentLength = totalLength;
                    Stream stream = httpWebRequest.GetRequestStream();

                    foreach (byte[] b in postDatas)
                    {
                        stream.Write(b, 0, b.Length);
                    }


                    stream.Close();
                }


                httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                Stream responseStream = httpWebResponse.GetResponseStream();
                StreamReader streamReader = new StreamReader(responseStream, RequestInfo.Encoding);
                string html = streamReader.ReadToEnd();
                streamReader.Close();
                responseStream.Close();


                //currentTry = 0;

                webHeader = new WebHeaderCollection();
                webHeader = httpWebResponse.Headers;
                httpWebRequest.Abort();
                httpWebResponse.Close();


                foreach (Cookie cookie in httpWebResponse.Cookies)
                {
                    RequestInfo.Cookie.Add(cookie);
                }

                return html;
            }
            catch (Exception ex)
            {
                if (httpWebRequest != null)
                {
                    httpWebRequest.Abort();
                } if (httpWebResponse != null)
                {
                    httpWebResponse.Close();
                }
                Console.WriteLine("BaseHelper.Http.HttpHelper.cs.Get:" + ex.Message);
                return "";
            }
        }


        public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受  
        }

        public Stream GetStream(string url, string postData = null)
        {
            currentTry++;
            HttpWebRequest httpWebRequest = null;

            HttpWebResponse httpWebResponse = null;

            try
            {

                httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);
                if (RequestInfo.Proxy != null)
                    httpWebRequest.Proxy = RequestInfo.Proxy;
                httpWebRequest.CookieContainer = RequestInfo.Cookie;
                httpWebRequest.ContentType = RequestInfo.ContentType;
                httpWebRequest.ServicePoint.ConnectionLimit = maxTry;
                httpWebRequest.Referer = url;
                httpWebRequest.Accept = RequestInfo.Accept;
                httpWebRequest.UserAgent = RequestInfo.UserAgent;
                httpWebRequest.Method = postData == null ? "GET" : "POST";

                if (postData != null)
                {
                    byte[] byteRequest = RequestInfo.Encoding.GetBytes(postData);
                    httpWebRequest.ContentLength = byteRequest.Length;
                    Stream stream = httpWebRequest.GetRequestStream();
                    stream.Write(byteRequest, 0, byteRequest.Length);
                    stream.Close();
                }

                httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                Stream responseStream = httpWebResponse.GetResponseStream();
                currentTry--;
                foreach (Cookie cookie in httpWebResponse.Cookies)
                {
                    RequestInfo.Cookie.Add(cookie);
                }
                webHeader = new WebHeaderCollection();
                webHeader = httpWebResponse.Headers;
                return responseStream;
            }
            catch (Exception ex)
            {
                if (httpWebRequest != null)
                {
                    httpWebRequest.Abort();
                } 
                if (httpWebResponse != null)
                {
                    httpWebResponse.Close();
                }
                Console.WriteLine("BaseHelper.Http.HttpHelper.cs.GetStream:" + ex.Message);
                return null;
            }
        }

        public Image GetImage(string url, string postData = null)
        {
            Stream stream = GetStream(url, postData);
            Image ret = null;
            try
            {
                ret = Image.FromStream(stream);
            }
            catch (Exception ex)
            {
                Console.WriteLine("BaseHelper.Http.HttpHelper.cs.GetImage:" + ex.Message);
            }
            return ret;
        }
        public bool Download(string url, string localpath)
        {
            try
            {
                WebClient web = new WebClient();
                web.DownloadFile(url, localpath);
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}
